from py2neo import Graph
from py2neo import errors  # 关键：导入错误模块
import re
import time


# -------------------------- 通用工具函数（基础支撑） --------------------------
def connect_neo4j(uri, user, password):
    """
    连接Neo4j数据库
    :param uri: Neo4j连接地址（bolt协议）
    :param user: 用户名
    :param password: 密码
    :return: Graph对象 / None（连接失败）
    """
    try:
        graph = Graph(uri, auth=(user, password))
        # 测试连接有效性
        graph.run("MATCH () RETURN count(*) LIMIT 1").evaluate()
        print("✅ 成功连接Neo4j数据库！\n")
        return graph
    except errors.AuthError:
        print("❌ Neo4j认证失败：请检查用户名/密码是否正确！")
        return None
    except errors.ServiceUnavailable:
        print("❌ Neo4j服务不可用：请检查URI、端口或数据库容器状态！")
        return None
    except Exception as e:
        print(f"❌ 数据库连接异常：{str(e)}")
        return None


def execute_cypher(graph, cypher):
    """
    执行Cypher查询并返回格式化数据
    :param graph: Graph对象（数据库连接）
    :param cypher: Cypher查询语句
    :return: list[dict]（查询结果）/ None（执行失败）
    """
    try:
        start_time = time.time()
        result = graph.run(cypher).data()  # 返回字典列表（键：查询列名，值：结果）
        end_time = time.time()
        print(f"📊 查询耗时：{end_time - start_time:.4f} 秒，匹配到 {len(result)} 条数据\n")
        return result
    except errors.ClientError as e:
        print(f"❌ Cypher语法错误：{str(e)}")
        return None
    except Exception as e:
        print(f"❌ 查询执行异常：{str(e)}")
        return None


# -------------------------- 场景1：甜味剂类型 → 关联文献查询 --------------------------
def regex_sweetener_literature(question):
    """正则匹配：甜味剂类型查文献（如“天然植物提取物有什么文献？”）"""
    # 覆盖：带/不带书名号、“有什么/哪些”“文献/论文/研究报告”
    pattern = r'(?:《|“)?(.+?)(?:》|”)?(?:有什么|有哪些|有那些|包含哪些|涉及哪些)(?:文献|论文|研究报告)?(?:\?)?'
    match = re.search(pattern, question, re.IGNORECASE)  # 忽略大小写
    if match:
        return match.group(1).strip()  # 返回提取的“甜味剂类型名称”
    return None


def answer_sweetener_literature(graph, sweetener_name):
    """回答函数：根据甜味剂类型查询关联文献"""
    # Cypher：匹配“甜味剂类型 -[:研究论文]-> 论文名称”
    cypher = f"""
    MATCH (:甜味剂类型 {{name: '{sweetener_name}'}})-[:研究论文]->(paper:论文名称)
    RETURN paper.name AS 文献名称
    ORDER BY paper.source_row ASC  
    LIMIT 10; 
    """
    result = execute_cypher(graph, cypher)

    if not result:
        return f"抱歉，未找到「{sweetener_name}」相关的文献信息~"

    # 格式化结果（分点列出）
    answer = f"「{sweetener_name}」相关的文献如下（共{len(result)}条）：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['文献名称']}\n"
    return answer.strip()


# -------------------------- 场景2：论文名称 → 提及的致甜成分查询 --------------------------
def regex_paper_ingredient(question):
    """正则匹配：论文查致甜成分（如“《甜菊糖苷应用研究现状》提到了哪些致甜成分？”）"""
    # 覆盖：带书名号、“提到/涉及/包含”“致甜成分/致甜物质”
    pattern = r'(?:《|“)?(.+?)(?:》|”)?(?:提到了|涉及|包含)(?:哪些|什么)(?:致甜成分|致甜物质)?(?:\?)?'
    match = re.search(pattern, question, re.IGNORECASE)
    if match:
        return match.group(1).strip()  # 返回提取的“论文名称”（自动去除书名号）
    return None


def answer_paper_ingredient(graph, paper_name):
    """回答函数：根据论文名称查询提及的致甜成分"""
    # Cypher：匹配“论文名称 -[:致甜物质]-> 致甜成分名称”
    cypher = f"""
    MATCH (:论文名称 {{name: '{paper_name}'}})-[:致甜物质]->(ingredient:致甜成分名称)
    RETURN ingredient.name AS 致甜成分名称
    ORDER BY ingredient.source_row ASC
    """
    result = execute_cypher(graph, cypher)

    if not result:
        return f"抱歉，未找到《{paper_name}》中提及的致甜成分信息~"

    answer = f"《{paper_name}》中提及的致甜成分如下（共{len(result)}条）：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['致甜成分名称']}\n"
    return answer.strip()


# -------------------------- 场景3：致甜成分 → 特点（优点+缺点）查询 --------------------------
def regex_ingredient_features(question):
    """正则：提取致甜成分，匹配“优点/缺点/特点”问法"""
    pattern = r'''
        (?:什么是|哪些是)?\s*         # 兼容倒装（如“什么是X的优点”）
        (?:《|“)?                     # 可选左符号（书名号/引号）
        (.+?)                         # 核心：提取致甜成分名（如“甜菊糖苷”）
        (?:\(.*?\))?                  # 忽略括号别名（如“甜菊糖苷（瑞鲍迪甙A）”）
        (?:》|”)?                     # 可选右符号
        \s*(?:的|有)?\s*              # “的/有”可选（如“X的优点”“X有缺点”）
        (?:特点|优点|缺点|特性)       # 必须包含的属性词
        (?:是什么|有哪些)?\s*         # 兼容结尾疑问（如“X特点是什么”）
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_features(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:优点/缺点]->致甜成分的优点/缺点”"""
    # 合并查询（一次查优点+缺点，匹配导入的标签和关系）
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})
    OPTIONAL MATCH (i)-[:优点]->(adv:致甜成分的优点)
    OPTIONAL MATCH (i)-[:缺点]->(dis:致甜成分的缺点)
    RETURN 
      COLLECT(DISTINCT adv.name) AS 优点列表,
      COLLECT(DISTINCT dis.name) AS 缺点列表
    ORDER BY adv.source_row, dis.source_row
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的特点（优点/缺点）信息~"

    优点 = [item for item in result[0]["优点列表"] if item is not None]
    缺点 = [item for item in result[0]["缺点列表"] if item is not None]
    answer = f"「{ingredient_name}」的特点如下：\n"
    if 优点:
        answer += "✅ 优点：\n" + "\n".join([f"   {i+1}. {v}" for i, v in enumerate(优点)]) + "\n"
    if 缺点:
        answer += "❌ 缺点：\n" + "\n".join([f"   {i+1}. {v}" for i, v in enumerate(缺点)])
    return answer.strip()


# -------------------------- 场景4：致甜成分 → 应用场景 --------------------------
def regex_ingredient_application(question):
    """正则：提取致甜成分，匹配“应用场景/用在哪里”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*(?:用在哪里|应用场景|应用是什么|适用于什么场景|的应用)?\s*  # 多问法覆盖
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_application(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:应用于]->致甜成分的应用”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:应用于]->(app:致甜成分的应用)
    RETURN app.name AS 应用场景
    ORDER BY app.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的应用场景信息~"

    answer = f"「{ingredient_name}」的应用场景如下（共{len(result)}条）：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['应用场景']}\n"
    return answer.strip()


# -------------------------- 场景5：致甜成分 → 添加量及口感 --------------------------
def regex_ingredient_amount_taste(question):
    """正则：提取致甜成分，匹配“添加量及口感”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*的\s*(?:添加量|用量|添加量及口感)\s*及\s*(?:感受|口感)\s*是?(?:怎样的|如何)?\s*  # 多问法
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_amount_taste(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:添加量及口感]->致甜成分添加量及口感”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:添加量及口感]->(amt:致甜成分添加量及口感)
    RETURN amt.name AS 添加量及口感描述
    ORDER BY amt.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的添加量及口感信息~"

    answer = f"「{ingredient_name}」的添加量及口感如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['添加量及口感描述']}\n"
    return answer.strip()


# -------------------------- 场景6：致甜成分 → 添加方法（实验方法） --------------------------
def regex_ingredient_add_method(question):
    """正则：提取致甜成分，匹配“添加方法/实验方法”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*(?:怎么添加|如何添加|添加方式|添加方法|实验方法)\s*是?(?:\?)?  # 多问法
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_add_method(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:实验方法]->致甜成分实验方法”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:实验方法]->(method:致甜成分实验方法)
    RETURN method.name AS 添加方法描述
    ORDER BY method.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的添加方法（实验方法）信息~"

    answer = f"「{ingredient_name}」的添加方法如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['添加方法描述']}\n"
    return answer.strip()


# -------------------------- 场景7：致甜成分 → 相对甜度 --------------------------
def regex_ingredient_sweetness(question):
    """正则：提取致甜成分，匹配“相对甜度”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*的\s*(?:相对甜度|甜度)\s*是?(?:多少|如何)?\s*  # 多问法
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_sweetness(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:相对甜度]->致甜成分相对甜度”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:相对甜度]->(sweet:致甜成分相对甜度)
    RETURN sweet.name AS 相对甜度描述
    ORDER BY sweet.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的相对甜度信息~"

    answer = f"「{ingredient_name}」的相对甜度如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['相对甜度描述']}\n"
    return answer.strip()


# -------------------------- 场景8：致甜成分 → 甜味持久性 --------------------------
def regex_ingredient_duration(question):
    """正则：提取致甜成分，匹配“甜味持久性”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*的甜味\s*(?:持久|持续|留存)性\s*(?:如何|怎么样|是多少)?\s*  # 多问法
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_duration(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:持久性]->甜味持久性”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:持久性]->(dur:甜味持久性)
    RETURN dur.name AS 持久性描述
    ORDER BY dur.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的甜味持久性信息~"

    answer = f"「{ingredient_name}」的甜味持久性如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['持久性描述']}\n"
    return answer.strip()


# -------------------------- 场景9：致甜成分 → 烟叶/烟丝中含量及迁移率 --------------------------
def regex_ingredient_transfer(question):
    """正则：提取致甜成分，匹配“含量及迁移率”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*在\s*(?:烟叶|烟丝|烟草|烟草制品)\s*中的\s*(?:含量|迁移率|含量及迁移率)\s*是?(?:多少|如何)?\s*  # 多问法
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_transfer(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:含量及迁移率]->致甜成分烟丝中的含量及迁移率”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:含量及迁移率]->(trans:致甜成分烟丝中的含量及迁移率)
    RETURN trans.name AS 含量及迁移率描述
    ORDER BY trans.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」在烟叶/烟丝中的含量及迁移率信息~"

    answer = f"「{ingredient_name}」在烟叶/烟丝中的含量及迁移率如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['含量及迁移率描述']}\n"
    return answer.strip()


# -------------------------- 新增场景10：致甜成分 → 添加部位 --------------------------
def regex_ingredient_position(question):
    """【添加部位场景专用正则】强制提取完整成分名（如“蔗糖”“甜菊糖苷（瑞鲍迪甙A）”）"""
    # 关键：用否定字符集 [^的...] 限定成分名范围，只在遇到“的”时停止
    pattern = r'(?:《|“)?([^的《》“”（）\?\s]+(?:\([^）]+\))?)(?:》|”)?的(?:添加部位|添加位置|添加处)是?(?:什么|哪里)?\??'
    # 必须加 re.UNICODE（确保中文匹配），re.IGNORECASE（忽略大小写）
    match = re.search(pattern, question, re.IGNORECASE | re.UNICODE)

    # 调试：打印提取过程（方便定位问题，后续可删除）
    if match:
        extracted = match.group(1).strip()
        print(f"【调试】正则提取结果：{extracted}")  # 正常应打印“蔗糖”
        return extracted
    else:
        print(f"【调试】正则未匹配到成分名，问题句：{question}")
        return None


def answer_ingredient_position(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:添加部位]->致甜成分的添加部位”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:添加部位]->(pos:致甜成分的添加部位)
    RETURN pos.name AS 添加部位描述
    ORDER BY pos.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的添加部位信息~"

    answer = f"「{ingredient_name}」的添加部位如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['添加部位描述']}\n"
    return answer.strip()


# -------------------------- 新增场景11：致甜成分 → 香气 --------------------------
def regex_ingredient_aroma(question):
    """正则：提取致甜成分，匹配“香气”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*的\s*(?:香气|香味|气味)\s*是?(?:什么|如何)?\s*  # 多问法
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_aroma(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:香气]->致甜成分的香气”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:香气]->(aroma:致甜成分的香气)
    RETURN aroma.name AS 香气描述
    ORDER BY aroma.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的香气信息~"

    answer = f"「{ingredient_name}」的香气如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['香气描述']}\n"
    return answer.strip()


# -------------------------- 新增场景12：致甜成分 → 评吸方法 --------------------------
def regex_ingredient_smoking_method(question):
    """正则：提取致甜成分，匹配“评吸方法”问法"""
    pattern = r'''
        (?:《|“)?                     # 可选左符号
        (.+?)                         # 提取致甜成分名
        (?:\(.*?\))?                  # 忽略括号别名
        (?:》|”)?                     # 可选右符号
        \s*的\s*(?:评吸方法|评吸方式|品鉴方法)\s*是?(?:什么|如何)?\s*  # 多问法
        (?:\?)?                       # 可选问号
    '''
    match = re.search(pattern, question, re.IGNORECASE | re.VERBOSE)
    return match.group(1).strip() if match else None


def answer_ingredient_smoking_method(graph, ingredient_name):
    """查询：匹配导入程序的“致甜成分名称-[:评吸方式]->评吸方法”"""
    cypher = f"""
    MATCH (i:致甜成分名称 {{name: '{ingredient_name}'}})-[:评吸方式]->(smoke:评吸方法)
    RETURN smoke.name AS 评吸方法描述
    ORDER BY smoke.source_row ASC
    """
    result = execute_cypher(graph, cypher)
    if not result:
        return f"抱歉，未找到「{ingredient_name}」的评吸方法信息~"

    answer = f"「{ingredient_name}」的评吸方法如下：\n"
    for idx, item in enumerate(result, 1):
        answer += f"{idx}. {item['评吸方法描述']}\n"
    return answer.strip()


# -------------------------- 主函数（调度中心） --------------------------
def main():
    # -------------------------- 配置信息（请根据你的Neo4j修改） --------------------------
    NEO4J_URI = "bolt://47.120.77.67:7687"
    NEO4J_USER = "neo4j"
    NEO4J_PASSWORD = "053116wj"

    # 1. 连接数据库
    graph = connect_neo4j(NEO4J_URI, NEO4J_USER, NEO4J_PASSWORD)
    if not graph:
        return  # 连接失败则退出

    # 2. 定义查询场景映射（正则函数 → 回答函数）
    query_scenarios = [
        (regex_sweetener_literature, answer_sweetener_literature),  # 场景1
        (regex_paper_ingredient, answer_paper_ingredient),  # 场景2
        (regex_ingredient_features, answer_ingredient_features),  # 场景3
        (regex_ingredient_application, answer_ingredient_application),  # 场景4
        (regex_ingredient_amount_taste, answer_ingredient_amount_taste),  # 场景5
        (regex_ingredient_add_method, answer_ingredient_add_method),  # 场景6
        (regex_ingredient_sweetness, answer_ingredient_sweetness),  # 场景7
        (regex_ingredient_duration, answer_ingredient_duration),  # 场景8
        (regex_ingredient_transfer, answer_ingredient_transfer)  # 场景9
    ]

    # 3. 交互：接收用户问题并回答
    print("📝 请输入你的查询问题（输入“退出”结束）：")
    while True:
        user_question = input("\n用户：")
        if user_question.strip().lower() in ["退出", "quit", "exit"]:
            print("👋 感谢使用，再见！")
            break
        if not user_question.strip():
            print("❌ 请输入有效的问题~")
            continue

        # 4. 遍历场景，匹配并回答
        matched = False
        for regex_func, answer_func in query_scenarios:
            keyword = regex_func(user_question)
            if keyword:
                print(f"🔍 正在查询「{keyword}」相关信息...")
                answer = answer_func(graph, keyword)
                print(f"\n查询结果：{answer}")
                matched = True
                break
        if not matched:
            print("\n答：抱歉，我暂时无法理解你的问题~ 可尝试以下问法：")
            print("  - 甜味剂查文献：“天然植物提取物有什么文献？”")
            print("  - 论文查成分：“《甜菊糖苷应用研究现状》提到了哪些致甜成分？”")
            print("  - 成分查特点：“甜菊糖苷有什么特点？”")
            print("  - 成分查应用：“山梨醇用在哪里？”")


if __name__ == "__main__":
    main()